/**
 * XQuery to Scala Translator
 * Fatemeh Borran-Dejnabadi
 * 15 December 2004
 */

package xquery2src;

import Types._;

/** This class provides a representation for types in misc
 */
class Type {

  /** This method can be used to check if two types are equal.
   */
  def isSameType(that:Type):boolean = {
    return (this == that) || (this == BAD_TYPE) || (that == BAD_TYPE);
  }
  
  /** This method checks if the provided type is a super type
   *  of the receiver.
   */
  def isSubType(that:Type):boolean = {
    return (this == BAD_TYPE) ||
    (that == BAD_TYPE) ||
    (this == BOTTOM_TYPE) ||
    (that == ANY_TYPE) ||
    isSameType(that) ||
    ((this == ATTRIBUTE_TYPE) && (that == ELEMENT_TYPE)) ||
    ((this == ELEMENT_TYPE) && (that == COLLECTION_TYPE)) ||
    ((this == ATTRIBUTE_TYPE) && (that == COLLECTION_TYPE));
  }
  
  /** Return the less specific type of this type and 'that'.
   */
  def max(that:Type):Type = {
    if (isSubType(that))
      return that;
    if (that.isSubType(this))
      return this;
    return BAD_TYPE;
  }
  
  /** Returns a textual representation of this type.
   */
  override def toString():String = {
    if (this == NO_TYPE)
      return "<none>";
    if (this == BAD_TYPE)
      return "<bad>";
    if (this == BOTTOM_TYPE)
      return "<bottom>";
    if (this == ANY_TYPE)
      return "Any";
    if (this == UNIT_TYPE)
      return "Unit";
    if (this == INT_TYPE)
      return "Int";
    if (this == STRING_TYPE)
      return "String";
    if (this == ELEMENT_TYPE)
      return "Element";
    if (this == ATTRIBUTE_TYPE)
      return "Attribute";
    if (this == COLLECTION_TYPE)
      return "Collection";
    throw new Error();
  }

}
/** Representation for function types.
 */
case class FunType(params:Array[Type], resType:Type) extends Type {
  
  /** This method can be used to check if two types are equal.
   */
  override def isSameType(that:Type):boolean = {
    if (that == BAD_TYPE) {
      return true;
    }
    else if (that.isInstanceOf[FunType]) {
      if (resType.isSameType((that.asInstanceOf[FunType]).resType)) {
        if (params.length == (that.asInstanceOf[FunType]).params.length) {
	  var i:int = 0;
          while (i < params.length) {
            if (!((params.apply(i)).isSameType((that.asInstanceOf[FunType]).params.apply(i))))
              return false;
	    i = i + 1;
          }
          return true;
        }
        else {
          return false;
	}
      }
      else {
        return false;
      }
    }
    else {
      return false;
    }
  }

  /** This method checks if the provided type is a super type
   *  of the receiver.
   */
  override def isSubType(that:Type):boolean = {
    if ((that == ANY_TYPE) || (that == BAD_TYPE) ||
        (that == COLLECTION_TYPE)) {
          return true;
    }
    if (that.isInstanceOf[FunType]){
      if (resType.isSubType((that.asInstanceOf[FunType]).resType)) {
        if (params.length == (that.asInstanceOf[FunType]).params.length) {
	  var i:int = 0;
          while (i < params.length) {
            if (!(((that.asInstanceOf[FunType]).params.apply(i)).isSubType(params.apply(i)))) {
              return false;
            }
	    i = i + 1;
          }
          return true;
        }
        else {
          // le nombre de params ne correspond pas
          return false;
        }
      }
      else {
        // les restypes ne jouent pas
        return false;
      }
    }
    else{
      // that n'est pas funType, alors on regarde le type de retour de that
      if (resType.isSubType(that)) {
        return true;
      }
      else {
        return false;
      }
    }
  }
  
  /** Returns a textual representation of this type.
   */
  override def toString():String = {
    var s:String = "(";
    var i:int = 0;
    while (i < params.length) {
      s = s + params.apply(i).toString() + ',';
      i = i + 1;
    }
    s = s + ") => " + resType.toString();
    return s;
  }
  
}

